package cn.core.sign.interceptors;

import cn.core.sign.eo.Sessions;
import cn.core.sign.mapper.SessionsMapper;
import cn.core.sign.qo.SessionsQO;
import cn.core.tool.context.CoreContextData;
import cn.core.tool.context.CurrentContextData;
import cn.core.tool.util.CoreTool;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.Duration;

/**
 * 请求拦截器
 */
@Log4j2
@Configuration
public class AuthorizationInterceptor implements HandlerInterceptor {

  @Resource
  private Gson gson;

  @Resource
  private SessionsMapper sessionsMapper;

  @Value("${proconf.enable-http-request-time-diff-validation}")
  private boolean enableHttpRequestTimeDiffValidation;

  @Value("${proconf.http-request-time-diff}")
  private long httpRequestTimeDiff;

  @Value("${proconf.enable-session-redis}")
  private boolean enableSessionRedis;

  @Resource
  private StringRedisTemplate stringRedisTemplate;

  @Value("${proconf.session-redis-key-prefix}")
  private String sessionRedisKeyPrefix;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    try {
      if (200 == response.getStatus() && "POST".equals(request.getMethod())) {
        long times = System.currentTimeMillis();
        String decodeToken = CoreTool.decodeRSAByPrivateKey(request.getHeader("Authorization"), CoreTool.PRIVATE_KEY);
        String token = decodeToken.substring(0, 32);
        if (enableHttpRequestTimeDiffValidation) {
          long requestTimeDiff = times - Long.valueOf(decodeToken.substring(32));
          if (requestTimeDiff > 0l && requestTimeDiff < httpRequestTimeDiff) {
            if (CoreTool.isNotNullStr(token)) {
              if (enableSessionRedis) {
                String redisTokenStr = stringRedisTemplate.opsForValue().get(sessionRedisKeyPrefix + token);
                if (CoreTool.isNotNullStr(redisTokenStr)) {
                  CurrentContextData redisCurrentContextData = gson.fromJson(redisTokenStr, new TypeToken<CurrentContextData>(){}.getType());
                  if ("Browser".equals(redisCurrentContextData.getLoginSide())) {
                    // 浏览器端登录
                    stringRedisTemplate.expire(sessionRedisKeyPrefix + token, Duration.ofMillis(redisCurrentContextData.getTokenExpireBrowser()));
                    CoreContextData.removeCurrentContextData();
                    CoreContextData.setCurrentContextData(redisCurrentContextData);
                  } else if ("Android".equals(redisCurrentContextData.getLoginSide())) {
                    // 安卓app登录
                  } else if ("ios".equals(redisCurrentContextData.getLoginSide())) {
                    // 苹果app登录
                  } else if ("Wechatapp".equals(redisCurrentContextData.getLoginSide())) {
                    // 微信小程序登录
                  } else {
                    response.sendError(401, "token 无效");
                    return false;
                  }
                } else {
                  response.sendError(401, "token 无效");
                  return false;
                }
              } else {
                Sessions sessions = sessionsMapper.pk(new SessionsQO().setId(token));
                if (CoreTool.isNotNullEo(sessions)) {
                  if ("Browser".equals(sessions.getLoginSide())) {
                    // 浏览器端登录
                    sessionsMapper.updateSome(new Sessions().setId(sessions.getId()).setCurrentTimes(times));
                    CoreContextData.removeCurrentContextData();
                    CoreContextData.setCurrentContextData(gson.fromJson(sessions.getSessionsInfo(), new TypeToken<CurrentContextData>(){}.getType()));
                  } else if ("Android".equals(sessions.getLoginSide())) {
                    // 安卓app登录
                  } else if ("ios".equals(sessions.getLoginSide())) {
                    // 苹果app登录
                  } else if ("Wechatapp".equals(sessions.getLoginSide())) {
                    // 微信小程序登录
                  } else {
                    response.sendError(401, "token 无效");
                    return false;
                  }
                } else {
                  response.sendError(401, "token 无效");
                  return false;
                }
              }
            } else {
              response.sendError(401, "token 无效");
              return false;
            }
          } else {
            response.sendError(401, "token 无效");
            return false;
          }
        } else {
          if (CoreTool.isNotNullStr(token)) {
            if (enableSessionRedis) {
              String redisTokenStr = stringRedisTemplate.opsForValue().get(sessionRedisKeyPrefix + token);
              if (CoreTool.isNotNullStr(redisTokenStr)) {
                CurrentContextData redisCurrentContextData = gson.fromJson(redisTokenStr, new TypeToken<CurrentContextData>(){}.getType());
                if ("Browser".equals(redisCurrentContextData.getLoginSide())) {
                  // 浏览器端登录
                  stringRedisTemplate.expire(sessionRedisKeyPrefix + token, Duration.ofMillis(redisCurrentContextData.getTokenExpireBrowser()));
                  CoreContextData.removeCurrentContextData();
                  CoreContextData.setCurrentContextData(redisCurrentContextData);
                } else if ("Android".equals(redisCurrentContextData.getLoginSide())) {
                  // 安卓app登录
                } else if ("ios".equals(redisCurrentContextData.getLoginSide())) {
                  // 苹果app登录
                } else if ("Wechatapp".equals(redisCurrentContextData.getLoginSide())) {
                  // 微信小程序登录
                } else {
                  response.sendError(401, "token 无效");
                  return false;
                }
              } else {
                response.sendError(401, "token 无效");
                return false;
              }
            } else {
              Sessions sessions = sessionsMapper.pk(new SessionsQO().setId(token));
              if (CoreTool.isNotNullEo(sessions)) {
                if ("Browser".equals(sessions.getLoginSide())) {
                  // 浏览器端登录
                  sessionsMapper.updateSome(new Sessions().setId(sessions.getId()).setCurrentTimes(times));
                  CoreContextData.removeCurrentContextData();
                  CoreContextData.setCurrentContextData(gson.fromJson(sessions.getSessionsInfo(), new TypeToken<CurrentContextData>(){}.getType()));
                } else if ("Android".equals(sessions.getLoginSide())) {
                  // 安卓app登录
                } else if ("ios".equals(sessions.getLoginSide())) {
                  // 苹果app登录
                } else if ("Wechatapp".equals(sessions.getLoginSide())) {
                  // 微信小程序登录
                } else {
                  response.sendError(401, "token 无效");
                  return false;
                }
              } else {
                response.sendError(401, "token 无效");
                return false;
              }
            }
          } else {
            response.sendError(401, "token 无效");
            return false;
          }
        }
      }
      return true;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  }

  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    CoreContextData.removeCurrentContextData();
  }

}
